﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;
using System.Resources;
using GenericValidation.Resources;

namespace GenericValidation
{
    public interface IValidationFactory
    {

        IValidation Resolve<T>();
        IValidation Resolve(Type itemType);
    }

    /// <summary>
    /// Handles the Validation definitions life cycle.
    /// </summary>
    public class ValidationFactory : IValidationFactory
    {
        public List<ValidationRegistration> Registration { get; set; }

        /// <summary>
        /// Loads/Resolves the Validation definitions from the entry <paramref name="assembly"/>.
        /// </summary>
        /// <param name="assembly">The assembly that contains the Validation definition.</param>
        public void LoadFromAssembly(Assembly assembly)
        {
            var types = assembly.GetTypes();
            this.Registration = (from p in types
                                 where p.GetInterface(typeof(IValidation).Name) != null && p.BaseType.IsGenericType
                                 select new ValidationRegistration()
                                 {
                                     ItemType = p.BaseType.GetGenericArguments()[0],
                                     ValidationType = p
                                 }).ToList();
        }

        public virtual IValidation Resolve<T>()
        {
            return this.Resolve(typeof(T));
        }

        /// <summary>
        /// Resolves the Validation&lt;<paramref name="itemType"/>&gt; registered definition
        /// </summary>
        /// <param name="itemType"></param>
        /// <returns></returns>
        public virtual IValidation Resolve(Type itemType)
        {
            var registration = this.Registration.Single(p => p.ItemType == itemType);
            var ctorParams = new ArrayList();
            var ctorTypes = new Type[] {typeof(IValidationFactory)};

            var paramCtor = registration.ValidationType.GetConstructor(ctorTypes);
            if (paramCtor != null && paramCtor.IsConstructor)
            {
                ctorParams.Add(this);
            }

            var theResult = Activator.CreateInstance(registration.ValidationType, ctorParams.ToArray()) as IValidation;
            return theResult;
        }
    }
}
